package com.autonavi.yunda.yunji.core.engine.handler;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.lindorm.client.TableService;
import com.alibaba.lindorm.client.WideColumnService;
import com.alibaba.lindorm.client.core.utils.Bytes;
import com.alibaba.lindorm.client.core.utils.StringUtils;
import com.alibaba.lindorm.client.core.widecolumnservice.WGet;
import com.alibaba.lindorm.client.core.widecolumnservice.WPut;
import com.alibaba.lindorm.client.core.widecolumnservice.WResult;
import com.alibaba.lindorm.client.dml.Condition;
import com.alibaba.lindorm.client.dml.QueryResults;
import com.alibaba.lindorm.client.dml.Row;
import com.alibaba.lindorm.client.dml.Select;

import com.autonavi.yunda.yunji.common.exception.AmapException;
import com.autonavi.yunda.yunji.common.exception.AmapExceptionCode;
import com.autonavi.yunda.yunji.common.utils.SpringUtil;
import com.autonavi.yunda.yunji.core.service.ILindormDBFactory;
import com.autonavi.yunda.yunji.core.service.ILindormTableDBFactory;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * Lindorm 数据处理
 */
@Slf4j
public class LindormHandler {
    private static final String FAMILY_NAME = "f1";
    private static final byte[] FAMILY_NAME_BYTES = Bytes.toBytes(FAMILY_NAME);

    private static WideColumnService getWideColumnService(String dbName) {
        ILindormDBFactory<WideColumnService> lindormDBFactory = SpringUtil.getBean(ILindormDBFactory.class);
        try {
            return lindormDBFactory.getInstance(dbName);
        } catch (Exception e) {
            log.error("从dbFactoryService获取数据源失败 dbName:{}", dbName, e);
            throw new AmapException(AmapExceptionCode.COMMON_SERVER_ERROR, "获取数据源失败", e);
        }
    }

    private static TableService getTableService(String dbName) {
        ILindormTableDBFactory<TableService> lindormDBFactory = SpringUtil.getBean(ILindormTableDBFactory.class);
        try {
            return lindormDBFactory.getInstance(dbName);
        } catch (Exception e) {
            log.error("从dbFactoryService获取数据源失败 dbName:{}", dbName, e);
            throw new AmapException(AmapExceptionCode.COMMON_SERVER_ERROR, "获取数据源失败", e);
        }
    }

    public static Map<String, String> mGet(String dbName, String tableName, List<WGet> gets, String valueName) throws Exception {
        Map<String, String> map = new HashMap<>();
        WResult[] results = getWideColumnService(dbName).batchGet(tableName, gets);
        if (results == null || results.length == 0) {
            return null;
        }
        for (WResult wResult : results) {
            if (StringUtils.isNullOrEmpty(Bytes.toString(wResult.getRowKey()))) {
                continue;
            }
            String keyStr = Bytes.toString(wResult.getRowKey());
            String value = Bytes.toString(wResult.getValue(FAMILY_NAME_BYTES, Bytes.toBytes(valueName)));
            map.put(keyStr, value);
        }
        return map;
    }

    public static Map<String/*RowKey*/, Map<String/*column*/, String/*value*/>> mGetByCols(String dbName, String tableName, List<WGet> gets, List<String> valueNameList) throws Exception {
        Map<String, Map<String, String>> map = new HashMap<>();
        WResult[] results = getWideColumnService(dbName).batchGet(tableName, gets);
        if (results == null || results.length == 0) {
            return null;
        }
        for (WResult wResult : results) {
            if (StringUtils.isNullOrEmpty(Bytes.toString(wResult.getRowKey()))) {
                continue;
            }
            String keyStr = Bytes.toString(wResult.getRowKey());
            Map<String, String> subMap = new HashMap<>();
            for (String valueName : valueNameList) {
                String value = Bytes.toString(wResult.getValue(FAMILY_NAME_BYTES, Bytes.toBytes(valueName)));
                subMap.put(valueName, value);
            }
            map.put(keyStr, subMap);
        }
        return map;
    }


    public static void put(String dbName, String rowKey, String col, String value, String tableName) throws Exception {
        WPut put = new WPut(rowKey.getBytes());
        put.setOperationTimeout(0);
        put.add("f1".getBytes(), col.getBytes(), value.getBytes());
        getWideColumnService(dbName).put(tableName, put);
    }

    /**
     * 按列取值，并转成对应类的集合
     *
     * @param list
     * @param tableName
     * @param clazz
     * @param columnName
     * @return
     * @throws Exception
     */
    public static List selectList(String dbName, Condition list, String tableName, Type clazz, String... columnName) throws Exception {
        Select select = getTableService(dbName).select().from(tableName).columns(columnName).where(list);
        return select(select, clazz, columnName);
    }

    public static List select(Select select, Type clazz, String... columnName) throws Exception {
        QueryResults results = select.execute();

        List result = Lists.newArrayList();
        if (Objects.nonNull(results)) {
            Iterator<Row> it = results.iterator();
            Row row;
            while (it.hasNext()) {
                JSONObject obj = new JSONObject();
                row = it.next();
                for (String col : columnName) {
                    obj.put(col, row.getColumnValue(col).getValueObject());
                }
                if (org.apache.commons.collections4.MapUtils.isNotEmpty(obj)) {
                    result.add(JSON.parseObject(obj.toJSONString(), clazz));
                }
            }
        }
        return result;
    }
}
